//include for svm
#include "svm.h"
#include <stdio.h>
#include <cstdlib>  
#include <iostream> //FILE
#include <string.h> //String function
#include <vector> 	//vector
#include <errno.h>  //Erro handler
#include <math.h>
#include <float.h>
#include <stdarg.h>

#include <ctype.h>
#include <highgui.h>
#include <cv.h>

using namespace std;

//////////////////////////////////////////////////////////////////////////
/////////////////////////// SVM-predict Section ////////////////////////// 

struct svm_node *x;
struct svm_node *x2;
int max_nr_attr = 64;

struct svm_model* model;
int predict_probability=0;

static char *line = NULL;
static int max_line_len;

static char* readline(FILE *input)
{
	int len;
	
	if(fgets(line,max_line_len,input) == NULL)
		return NULL;

	while(strrchr(line,'\n') == NULL)
	{
		max_line_len *= 2;
		line = (char *) realloc(line,max_line_len);
		len = (int) strlen(line);
		if(fgets(line+len,max_line_len-len,input) == NULL)
			break;
	}
	return line;
}

void exit_input_error(int line_num)
{
	fprintf(stderr,"Wrong input format at line %d\n", line_num);
	exit(1);
}

struct svm_model* model3;
struct svm_model* loadModel(char* fileName)
//svm_model* loadModel(char* fileName)
{
	
	if((model3 = svm_load_model(fileName))==0)
	{
		printf("can't open model file\n");
	}else
	{ 
		printf("model file no problem\n");
		//printf("\n model->param.svm_type: %s\n",model->param.svm_type);//kung
	}
	return model3;
}

//void predict2(CvSeq** objectKeypoints,CvSeq** objectDescriptors,int descLength,int keypointCount)
void predict2(CvSeq** objectKeypoints,CvSeq** objectDescriptors,int descLength,int keypointCount, struct svm_model* model, int* predict_label_arr)
{
	int i;
	CvSeqReader reader;
     	cvStartReadSeq( *objectDescriptors, &reader );
	double predict_label;
	//int predict_label_arr[keypointCount];
		
	x2 = (struct svm_node *) malloc(129*sizeof(struct svm_node));
	
	//printf("DESSSCRIPTORRRRR\n");
	double time2 = (double)cvGetTickCount();
	for( i = 0; i < keypointCount; i++ ) {
    	const float* descriptor = (const float*)reader.ptr;
    	CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
    	//printf(" descriptor[0]:%f \n",descriptor[0]);  //kung
		//printf(" descriptor[1]:%f \n",descriptor[1]);  //kung
        	
		for(int k=0;k<(int)(descLength/4);k++)
		{
			int j=4*k;
			x2[j].index = j+1 ; x2[j].value=descriptor[j+1];
			x2[j+1].index = j+2 ; x2[j+1].value=descriptor[j+2];
			x2[j+2].index = j+3 ; x2[j+2].value=descriptor[j+3];
			x2[j+3].index = j+4 ; x2[j+3].value=descriptor[j+4];

			/*if(i==0){
			printf(" %d:%f ",x2[j].index,x2[j].value);
			printf(" %d:%f ",x2[j+1].index,x2[j+1].value);
			printf(" %d:%f ",x2[j+2].index,x2[j+2].value);
			printf(" %d:%f ",x2[j+3].index,x2[j+3].value);
			}*/
		}
		//x2[descLength].index = descLength+1; x2[descLength].value=-1;
		//if(i==1) {printf(" %d:%f \n",x2[descLength].index,x2[descLength].value);}
		x2[descLength].index =-1; //kung
		
		double time1 = (double)cvGetTickCount();
		predict_label = svm_predict(model,x2);
		time1 = (double)cvGetTickCount() - time1;
		//if(i==1){  printf("\n- Time predict 1 descriptor: %f ms",(time1/(cvGetTickFrequency()*1000.))); }
		predict_label_arr[i] = (int)predict_label; 
		//printf("\n i: %d predict_label_arr[i]: %d",(i+1),predict_label_arr[i]);
		//printf("\n i: %d predict_label: %f",i,predict_label);
    }
    time2 = (double)cvGetTickCount() - time2;
    //printf("\n- Time predict %d descriptor: %f ms",keypointCount,(time2/(cvGetTickFrequency()*1000.)));

	//printf("\n");
	
	free(x2);
	//return predict_label_arr;
	
}

//void predict(FILE *input, FILE *output)
vector<int> predict(FILE *input, FILE *output)
{
	int correct = 0;
	int total = 0;
	double error = 0;
	double sump = 0, sumt = 0, sumpp = 0, sumtt = 0, sumpt = 0;

	int svm_type=svm_get_svm_type(model);
	int nr_class=svm_get_nr_class(model);
	double *prob_estimates=NULL;
	int j;

	if(predict_probability)
	{
		if (svm_type==NU_SVR || svm_type==EPSILON_SVR)
			printf("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=%g\n",svm_get_svr_probability(model));
		else
		{
			int *labels=(int *) malloc(nr_class*sizeof(int));
			svm_get_labels(model,labels);
			prob_estimates = (double *) malloc(nr_class*sizeof(double));
			fprintf(output,"labels");		
			for(j=0;j<nr_class;j++)
				fprintf(output," %d",labels[j]);
			fprintf(output,"\n");
			free(labels);
		}
	}

	////// Ice added on 24 January 2010 //////
	// Vector for storing predict_label
	vector<int> predict_label_vec;
	printf("max_nr_attr: %d \n",max_nr_attr);
	printf("sizeof(svm_node): %d \n",sizeof(struct svm_node));
	printf("max_nr_attr*sizeof(struct svm_node): %d \n",max_nr_attr*sizeof(struct svm_node));
	int flag = 0 ; // Just for flag for print, can be deleted
	//////////////////////////////////////////

	max_line_len = 1024;
	line = (char *)malloc(max_line_len*sizeof(char));
	while(readline(input) != NULL)
	{
		int i = 0;
		double target_label, predict_label;
		char *idx, *val, *label, *endptr;
		int inst_max_index = -1; // strtol gives 0 if wrong format, and precomputed kernel has <index> start from 0

		label = strtok(line," \t");
		target_label = strtod(label,&endptr);
		if(endptr == label)
			exit_input_error(total+1);

		int count = 0;
	
		while(1)
		{
			if(i>=max_nr_attr-1)	// need one more for index = -1
			{
				max_nr_attr *= 2;
				x = (struct svm_node *) realloc(x,max_nr_attr*sizeof(struct svm_node));
			}

			idx = strtok(NULL,":");
			val = strtok(NULL," \t");

			if(val == NULL)
				break;
			errno = 0;
			x[i].index = (int) strtol(idx,&endptr,10);
			if(endptr == idx || errno != 0 || *endptr != '\0' || x[i].index <= inst_max_index)
				exit_input_error(total+1);
			else
				inst_max_index = x[i].index;

			errno = 0;
			x[i].value = strtod(val,&endptr);
			if(endptr == val || errno != 0 || (*endptr != '\0' && !isspace(*endptr)))
				exit_input_error(total+1);

			//if(flag==0) printf(" index %d value %f sizeof(index) %d sizeof(value) %d sizeof(long) %d sizeof(decimal) %d\n ",x[i].index, x[i].value,sizeof(x[0].index),sizeof(x[0].value),sizeof(long),sizeof(double));

			++i;
			count++;
		}
		if(flag==0)
		{
		 	printf(" How much in while loop %d  %d \n ",count,i);
			flag=1;
		}
		x[i].index = -1;

		if (predict_probability && (svm_type==C_SVC || svm_type==NU_SVC))
		{
			predict_label = svm_predict_probability(model,x,prob_estimates);
			fprintf(output,"%g",predict_label);
			for(j=0;j<nr_class;j++)
				fprintf(output," %g",prob_estimates[j]);
			fprintf(output,"\n");
		}
		else
		{
			//In P'Kung MATLAB code, model type is C_SVC with no predict_probability
			//predict_label is written to file here!!!!!
			predict_label = svm_predict(model,x);
			fprintf(output,"%g\n",predict_label);
		
			// Ice added this below line
			predict_label_vec.push_back(predict_label);
		}

		if(predict_label == target_label){
			++correct;
		}
		error += (predict_label-target_label)*(predict_label-target_label);
		sump += predict_label;
		sumt += target_label;
		sumpp += predict_label*predict_label;
		sumtt += target_label*target_label;
		sumpt += predict_label*target_label;
		++total;
	}
	if (svm_type==NU_SVR || svm_type==EPSILON_SVR)
	{
		printf("Mean squared error = %g (regression)\n",error/total);
		printf("Squared correlation coefficient = %g (regression)\n",
		       ((total*sumpt-sump*sumt)*(total*sumpt-sump*sumt))/
		       ((total*sumpp-sump*sump)*(total*sumtt-sumt*sumt))
		       );
	}
	else
		printf("Accuracy = %g%% (%d/%d) (classification)\n",
		       (double)correct/total*100,correct,total);
	if(predict_probability)
		free(prob_estimates);

	return predict_label_vec ;
}

void exit_with_help()
{
	printf(
	"Usage: svm-predict [options] test_file model_file output_file\n"
	"options:\n"
	"-b probability_estimates: whether to predict probability estimates, 0 or 1 (default 0); for one-class SVM only 0 is supported\n"
	);
	exit(1);
}




void svmpredict(std::vector<int>& objVec,std::vector<int>& imgVec){

	
	///////// ICE add /////////////////////////////
	//input.txt is file consist of object points descriptor.
	//input.txt is written in function ________ in file ______.cpp
	//Function svmpredict() opens 2 files, input.txt and input2.txt, to predict
	//with file model.txt

	FILE *input,*input2, *output,*output2;
	//int i;
	input = fopen("input.txt","r");
	if(input == NULL)
	{
		//fprintf(stderr,"can't open input file %s\n",argv[i]);
		printf("can't open input file for svm-predict\n");
		exit(1);
	}else
	{
		printf("no problem with input file\n");
	}

	//result.txt is result of prediction with model.txt.
	output = fopen("result.txt","w");
	if(output == NULL)
	{
		//fprintf(stderr,"can't open output file %s\n",argv[i+2]);
		printf("can't open result.txt to write result for prediction\n");
		exit(1);
	}else
	{
		printf("no problem with result file\n");
	}

	//This model.txt get from training using svm-train.
	if((model = svm_load_model("model4.txt"))==0)
	{
		printf("can't open model file\n");
	}else
	{ 
		printf("model file no problem\n");
	}
		
	x = (struct svm_node *) malloc(max_nr_attr*sizeof(struct svm_node));
	printf("before predict\n");
	objVec = predict(input,output);
	printf(" predictResult size %d \n",objVec.size());
	printf("predict finish\n");

	svm_destroy_model(model);
	free(x);
	free(line);
	fclose(input);
	fclose(output);

	//TO-DO: Optimize don't repeat yourself
	////////// Code below duplicate with above //////////////////////
	input2 = fopen("input2.txt","r");
	if(input2==NULL)
	{
		printf("can't open input file #2 for svm-predict\n");
		exit(1);
	}else
	{
		printf("no problem with input file #2 \n");
	}

	output2 = fopen("result2.txt","w");
	if(output2==NULL)
	{
		printf("can't open result2.txt to write result for prediction\n");
	}else
	{
		printf("no problem with result2 file\n");
	}	

	//This model.txt get from training using svm-train.
	if((model = svm_load_model("model4.txt"))==0)
	{
		printf("can't open model file\n");
	}else
	{ 
		printf("model file no problem\n");
	}
		
	x = (struct svm_node *) malloc(max_nr_attr*sizeof(struct svm_node));
	printf("before predict\n");
	imgVec = predict(input2,output2);
	printf(" predictResult size %d \n",imgVec.size());
	printf("predict finish\n");

	svm_destroy_model(model);
	free(x);
	free(line);
	fclose(input2);
	fclose(output2);


	///////////////////////////////////////////////
}
////////////////////////// End SVM-Predict ///////////////////////////////
//////////////////////////////////////////////////////////////////////////

 
//void getNewClassifiedPoint(vector<int> objLabel,vector<int> predicResObjPoint,CvSeq** cObjKeypoints, const CvSeq* objectKeypoints, CvSeq** cObjDscr, const CvSeq* objectDescriptors,CvMemStorage* storage )
void getNewClassifiedPoint(vector<int> objLabel,vector<int> predicResObjPoint,CvSeq** objectKeypoints,CvSeq** objectDescriptors)
{

	int count=0;
	unsigned int i;
	int deletedPosition;


	//Assert label size and prediction result size
	if(objLabel.size() == predicResObjPoint.size())
	{	

		for(i=0;i<predicResObjPoint.size();i++)
		{
			//if predict result is not same as label, it means that prediction is wrong 
			if(predicResObjPoint[i]!=objLabel[i])
			{
				if(count==0)
				{
					deletedPosition = i;
				}else
				{
					//Due to cvSeqRemove() always reduces size of sequence,
					//deletedPosition have to minus with 'count'
					deletedPosition = i - count ; 
				}
				cvSeqRemove(*objectDescriptors,deletedPosition);
				cvSeqRemove(*objectKeypoints,deletedPosition);
			
				count++;
			}
		}
		printf("---Number of non-pineapple point : %d \n",count);

	}
	
	
}



